#include "PrecompiledHeader_FileSysMgr.h"
#include "FileSys.h"

/*--------------------------------------------------------------------------*/
std::vector<DataSource*> FileSys::_datasources;
std::vector<IParser*> FileSys::_parsers;
std::map<std::string, DataSource*> FileSys::_allfiles;
std::map<std::string, IParser*> FileSys::_allparsers;
/*--------------------------------------------------------------------------*/

void FileSys::Init()
{
	_parsers.push_back(new XMLParser());
	_parsers.push_back(new TTFParser());
}

/*--------------------------------------------------------------------------*/

void FileSys::AddSource( const std::string& path )
{
	_datasources.push_back(new DataSource(path));
	DataSource* ds = _datasources.back();

	ds->UpdateAll();
}

/*--------------------------------------------------------------------------*/

IFiletype* FileSys::RegisterFile( FileDesc* desc )
{
	if (desc)
	{
		auto iter = _allfiles.find(desc->GetFullname());
		AssertLogC(iter != _allfiles.end(), "Duplicate files in filesystem: %s", desc->GetFullname().c_str());
		
		/*--------------------------------------------------------------------------*/

		auto parser = _allparsers.find(desc->GetExtension());

		if (parser != _allparsers.end())
		{
			IParser* p = parser->second;
			IFiletype* f = (IFiletype*) p->Load(desc);

			_allfiles[f->GetFilename()] = desc->GetOwner();
			AssertLogC(desc->GetOwner() == NULL, "NULL as owner is not permitted");

			return f;
		}
		else 
		{
			AssertLogE(true, "Unknown filetype: %s", desc->GetExtension().c_str());
			return NULL;
		}
	}
}

/*--------------------------------------------------------------------------*/

void FileSys::UnregisterFile( IFiletype* file )
{
	if (file)
	{
		auto iter = _allfiles.find(file->GetFilename());
		AssertLogC(iter == _allfiles.end(), "File does not exist in filesysyrm: %s", file->GetFilename().c_str());
		_allfiles.erase(iter);
	}
}

/*--------------------------------------------------------------------------*/

void FileSys::Dump()
{
	std::cout << "#rDataSources:" << std::endl;

	for (auto iter = _datasources.begin(); iter != _datasources.end(); ++iter)
	{
		AssertLogC(*iter == NULL, "Detected NULL in _datasources");
		std::cout << "Path: " << (*iter)->GetPath() << "\n#c    Total files: " << (*iter)->GetFilesList().size() << std::endl;
	}

	/*--------------------------------------------------------------------------*/

	std::cout << "#rAllKnownFiles:" << std::endl;

	for (auto iter = _allfiles.begin(); iter != _allfiles.end(); ++iter)
	{
		const std::string& filename = iter->first;
		DataSource* dataSource = iter->second;
		AssertLogC(dataSource == NULL, "NULL as DataSource detected!");

		std::cout << "At: " << dataSource->GetPath() << "     File: " << iter->first << std::endl;
	}
}

/*--------------------------------------------------------------------------*/

void FileSys::RegisterParser( IParser* parser, const std::string& ext )
{
	AssertLogC(ext[0] != '.', "File extension should begin with dot!");

	if (parser)
	{
		auto iter = _allparsers.find(ext);
		AssertLogC(iter != _allparsers.end(), "Duplicate extensions parser: %s", ext.c_str());
		_allparsers[ext] = parser;
	}
}

/*--------------------------------------------------------------------------*/

void FileSys::UnregisterParser( IParser* parser )
{
	for (auto iter = _allparsers.begin(); iter != _allparsers.end(); )
	{
		if (iter->second == parser)
		{
			iter = _allparsers.erase(iter);
		}
		else
		{
			++iter;
		}
	}

	for (auto iter = _parsers.begin(); iter != _parsers.end(); )
	{
		if (*iter == parser)
		{
			iter = _parsers.erase(iter);
		}
		else
		{
			++iter;
		}
	}
}

/*--------------------------------------------------------------------------*/

IFiletype* FileSys::GetFile( const std::string& name )
{
	auto ds = _allfiles.find(name);

	if (ds == _allfiles.end())
	{
		AssertLogC(true, "File %s not found!", name.c_str());
		return NULL;
	}
	
	DataSource* datasource = ds->second;
	
	if (datasource == NULL)
	{
		AssertLogC(true, "NULL in datasources?");
		return NULL;
	}

	IFiletype* file = datasource->GetFile(name);

	if (file == NULL)
	{
		AssertLogC(true, "File %s file not found in datasource!", name.c_str());
		return NULL;
	}
	
	return file;
}

/*--------------------------------------------------------------------------*/
